#include "tvcanvas.h"
#include <QApplication>
#include <QDesktopWidget>
#include <QDebug>
#include <QFile>
#include <qjson/parser.h>
#include <QQmlContext>
#include <QMetaObject>
#include <QQuickItem>
#include <QDirIterator>
#include "directoryscanner.h"
#include "runningline.h"
#include <QQmlEngine>

TvCanvas::TvCanvas(QObject *parent) :
    QObject(parent)
{
    m_qmlViewer = new QtQuick2ApplicationViewer();
    if (!loadConfig()) {
        m_qmlViewer->setMainQmlFile(QStringLiteral("qml/tv/ErrorScreen.qml"));
        m_qmlViewer->show();
        qWarning() << "Load config fail";
        return;
    }
    setupServer();
    m_qmlViewer->rootContext()->setContextProperty("qrs", m_qrsServer->service());
    m_qmlViewer->rootContext()->setContextProperty("ctrl", this);
    m_cached = new CachedImageProvider();
    m_qmlViewer->engine()->addImageProvider("cache", m_cached);
    qmlRegisterType<RunningLine>("com.romix.lab", 1, 0, "RunningLineX");
    setupWindow();
    m_qmlRoot = m_qmlViewer->rootObject();
    setupSlideshow();
    setupVideoPlayer();
    setupRunningLine();
    setupMessage();
    setupWatchers();
    setupSchedule();
}

bool TvCanvas::loadConfig()
{
    QFile file("config.json");
    if (!file.open(QIODevice::ReadOnly))
        return false;
    QJson::Parser parser;
    bool ok;
    m_config = parser.parse(&file, &ok).toMap();
    file.close();
    return ok;
}

void TvCanvas::setupWindow()
{
    m_qmlViewer->setMainQmlFile(QStringLiteral("qml/tv/main.qml"));
    int n = -1;
    if (m_config.contains("fullscreen_on")) {
        n = m_config["fullscreen_on"].toInt();
        if (n != -1) {
            QRect res = QApplication::desktop()->screenGeometry(n);
            m_qmlViewer->setPosition(res.x(), res.y());
            m_qmlViewer->showFullScreen();
        }
    }
    if (n == -1)
        m_qmlViewer->show();
}

void TvCanvas::setupServer()
{
    quint32 port = 8087;
    if (m_config.contains("qrs_port"))
        port = m_config["qrs_port"].toInt();
    m_qrsServer = new Server(port, this);
    m_service = m_qrsServer->service();
}

void TvCanvas::setupSlideshow()
{
    QVariantMap conf = m_config["slides"].toMap();
    DirectoryScanner sc(conf["folder"].toString());
    m_slides = sc.files();
    m_cached->cache(m_slides);
    foreach (QString img, m_slides)
        emit addSlide(img);
    if (conf["started"].toBool())
        emit m_service->startSlideshow();
}

void TvCanvas::setupVideoPlayer()
{
    QVariantMap conf = m_config["videos"].toMap();
    DirectoryScanner sc(conf["folder"].toString());
    m_videos = sc.files();
    foreach (QString video, m_videos)
        emit addVideo(video);
    if (conf["started"].toBool())
        emit m_service->startVideos();
}

void TvCanvas::setupRunningLine()
{
    QVariantMap conf = m_config["running_line"].toMap();
    if (conf.contains("text"))
        emit m_service->setRunningText(conf["text"].toString());
    if (conf.contains("color"))
        emit m_service->setRunningColor(conf["color"].toString());
    if (conf.contains("speed"))
        emit m_service->setRunningSpeed(conf["speed"].toInt());
    if (conf["started"].toBool())
        emit m_service->startRunningLine();
}

void TvCanvas::setupMessage()
{
    QVariantMap conf = m_config["message"].toMap();
    m_qmlRoot->setProperty("messages_folder", conf["folder"]);
    if (conf.contains("text"))
        emit m_service->setMessageText(conf["text"].toString());
    if (conf.contains("type"))
        emit m_service->setMessageType(conf["type"].toString());
    if (conf["started"].toBool())
        emit m_service->startMessage();
}

void TvCanvas::setupWatchers()
{
    m_imgWatcher = new QFileSystemWatcher(this);
    m_imgWatcher->addPath(m_config["slides"].toMap()["folder"].toString());
    connect(m_imgWatcher, SIGNAL(directoryChanged(QString)),
            this, SLOT(imgFolderChange(QString)));
}

void TvCanvas::setupSchedule()
{
    connect(m_qrsServer->service(), SIGNAL(setTimeSchedule(int,QString)),
            this, SLOT(setTimeSchedule(int,QString)));
    QTimer *timer = new QTimer(this);
    timer->setInterval(1000);
    timer->setSingleShot(false);
    connect(timer, SIGNAL(timeout()),
            this, SLOT(timerTimeout()));

    QVariantMap conf = m_config["schedule"].toMap();
    setTimeSchedule(0, conf["slideshow"].toString());
    setTimeSchedule(1, conf["videos"].toString());
    setTimeSchedule(2, conf["running_line"].toString());
    qDebug() << m_onTime;
    qDebug() << m_offTime;
    timer->start();
}

void TvCanvas::imgFolderChange(const QString &path)
{
    DirectoryScanner sc(path);
    QStringList files = sc.files();
    qDebug() << files << m_slides;
    for (int i = 0; i < files.count(); ++i)
        if (!m_slides.contains(files[i])) {
            m_cached->add(files[i]);
            emit addSlide(files[i]);
            qDebug() << "add"  << files[i];
        }
    for (int i = 0; i < m_slides.count(); ++i)
        if (!files.contains(m_slides[i])) {
            qDebug() << "remove" << m_slides[i];
            m_cached->remove(m_slides[i]);
            emit removeSlide(m_slides[i]);

        }
    m_slides = files;
}

void TvCanvas::videoFolderChange(const QString &path)
{
    DirectoryScanner sc(path);
    QStringList files = sc.files();
    qDebug() << files << m_videos;
    for (int i = 0; i < files.count(); ++i)
        if (!m_videos.contains(files[i])) {
            emit addVideo(files[i]);
            qDebug() << "addV"  << files[i];
        }
    for (int i = 0; i < m_videos.count(); ++i)
        if (!files.contains(m_videos[i])) {
            qDebug() << "remove" << m_videos[i];
            emit removeVideo(m_videos[i]);

        }
    m_videos = files;
}

void TvCanvas::setTimeSchedule(const int &service, const QString &schedule)
{
    QStringList timeList = schedule.split(',', QString::SkipEmptyParts);
    QList<QTime> onTime;
    QList<QTime> offTime;
    for (int i = 0; i < timeList.count(); ++i) {
        QTime t = QTime::fromString(timeList[i], "hh:mm:ss");
        if (i % 2 != 0)
            offTime.append(t);
        else
            onTime.append(t);
    }
    if (m_onTime.count() <= service) {
        m_onTime.insert(service, onTime);
        m_offTime.insert(service, offTime);
    } else {
        m_onTime[service] = onTime;
        m_offTime[service] = offTime;
    }
}

TvCanvas::SEARCH_RESULT TvCanvas::findTime(int service, const QTime &curTime)
{
    for (int i = 0; i < m_onTime[service].count(); ++i) {
        QTime t = m_onTime[service][i];
        if (curTime.hour() == t.hour()
                && curTime.minute() == t.minute()
                && curTime.second() == t.second())
            return ON;
    }
    for (int i = 0; i < m_offTime[service].count(); ++i) {
        QTime t = m_offTime[service][i];
        if (curTime.hour() == t.hour()
                && curTime.minute() == t.minute()
                && curTime.second() == t.second())
            return OFF;
    }
    return NOT_FOUND;
}

void TvCanvas::timerTimeout() // schedule
{
    QTime curTime = QTime::currentTime();
//    qDebug() << curTime;
    SEARCH_RESULT res;
    qrs::TvService *service = m_qrsServer->service();
    res = findTime(0, curTime);
//    qDebug() << res;
    if (res == ON)
        emit service->startSlideshow();
    else if (res == OFF)
        emit service->stopSlideshow();
    res = findTime(1, curTime);
    if (res == ON)
        emit service->startVideos();
    else if (res == OFF)
        emit service->stopVideos();
    res = findTime(2, curTime);
    if (res == ON)
        emit service->startRunningLine();
    else if (res == OFF)
        emit service->stopRunningLine();
}
